{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Ablating neurons in an ensemble\n",
    "\n",
    "The model used here is a simple controlled integrator,\n",
    "as is shown in\n",
    "[this core Nengo example](https://www.nengo.ai/nengo/examples/controlled_integrator.html)."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "import numpy as np\n",
    "import matplotlib.pyplot as plt\n",
    "%matplotlib inline\n",
    "\n",
    "import nengo\n",
    "%load_ext nengo.ipynb"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "from nengo.utils.functions import piecewise\n",
    "\n",
    "with nengo.Network(label='Controlled Integrator') as model:\n",
    "    input_func = piecewise({0: 0, 0.2: 5, 0.3: 0, 0.44: -10, 0.54: 0, 0.8: 5, 0.9: 0})\n",
    "    control_func = piecewise({0: 1, 0.6: 0.5})\n",
    "\n",
    "    tau = 0.1\n",
    "\n",
    "    stim = nengo.Node(input_func)\n",
    "    control = nengo.Node(output=control_func)\n",
    "    ens = nengo.Ensemble(225, dimensions=2, radius=1.5)\n",
    "    nengo.Connection(stim, ens, transform=[[tau], [0]], synapse=tau)\n",
    "    nengo.Connection(control, ens[1])\n",
    "\n",
    "\n",
    "    nengo.Connection(ens, ens[0],\n",
    "                     function=lambda x: x[0] * x[1],\n",
    "                     synapse=tau)\n",
    "\n",
    "    ens_probe = nengo.Probe(ens, synapse=0.01)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "with nengo.Simulator(model) as sim:\n",
    "    sim.run(1.4)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "def plot():\n",
    "    t = sim.trange()\n",
    "    dt = t[1] - t[0]\n",
    "    input_sig = list(map(input_func, t))\n",
    "    control_sig = list(map(control_func, t))\n",
    "    ref = dt * np.cumsum(input_sig)\n",
    "\n",
    "    plt.figure(figsize=(6, 8))\n",
    "    plt.subplot(2, 1, 1)\n",
    "    plt.plot(t, input_sig, label='Input')\n",
    "    plt.xlim(right=t[-1])\n",
    "    plt.ylim(-11, 11)\n",
    "    plt.ylabel('Input')\n",
    "    plt.legend(loc=\"lower left\", frameon=False)\n",
    "\n",
    "    plt.subplot(2, 1, 2)\n",
    "    plt.plot(t, ref, 'k--', label='Exact')\n",
    "    plt.plot(t, sim.data[ens_probe][:,0], label='A (value)')\n",
    "    plt.plot(t, sim.data[ens_probe][:,1], label='A (control)')\n",
    "    plt.xlim(right=t[-1])\n",
    "    plt.ylim(-1.1, 1.1)\n",
    "    plt.xlabel('Time (s)')\n",
    "    plt.ylabel('x(t)')\n",
    "    plt.legend(loc=\"lower left\", frameon=False)\n",
    "plot()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The model is composed primarily of a single two-dimensional ensemble.\n",
    "The first dimension takes in input;\n",
    "the second dimension is a control signal.\n",
    "The ensemble is recurrently connected such that\n",
    "the ensemble integrates the input signal\n",
    "in its first dimension,\n",
    "as long as the control dimension is near 1.\n",
    "As can be seen above, it performs as expected."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "We can emulate the effects of ablating neurons in an ensemble\n",
    "(or, equivalently, the input connections to those neurons)\n",
    "by setting the encoder associated with them to 0.\n",
    "If we wish to fully ablate the neurons\n",
    "and silence them entirely,\n",
    "we can inject a constant negative current into them.\n",
    "We'll make a helper function so that we can do this\n",
    "for any ensemble."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "def ablate_ensemble(ens, proportion, sim, bias=True):\n",
    "    \"\"\"Ablate a proportion of the neurons in an ensemble.\n",
    "\n",
    "    The ablation is done by setting the encoder and gain associated\n",
    "    with a neuron to zero. Since no input current being injected,\n",
    "    the neuron will generally be silent. However, if there is direct\n",
    "    current injected with a neuron-to-neuron connection, then the\n",
    "    cell may still fire. To counter that in most cases, we set the\n",
    "    bias associated with the neuron to a large negative value.\n",
    "    \"\"\"\n",
    "\n",
    "    n_neurons = min(int(ens.n_neurons * proportion), ens.n_neurons)\n",
    "    idx = np.random.choice(np.arange(ens.n_neurons), replace=False, size=n_neurons)\n",
    "\n",
    "    encoder_sig = sim.signals[sim.model.sig[ens]['encoders']]\n",
    "    encoder_sig.setflags(write=True)\n",
    "    encoder_sig[idx] = 0.0\n",
    "    encoder_sig.setflags(write=False)\n",
    "\n",
    "    if bias:\n",
    "        bias_sig = sim.signals[sim.model.sig[ens.neurons]['bias']]\n",
    "        bias_sig.setflags(write=True)\n",
    "        bias_sig[idx] = -1000"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Note that this function requires a built `Simulator`.\n",
    "This is because decoders are determined during\n",
    "the build process, and do not exist when the model\n",
    "is originally specified.\n",
    "\n",
    "Let's see the effects of ablating 1% of the 225 neurons\n",
    "in the ensemble."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "with nengo.Simulator(model) as sim:\n",
    "    ablate_ensemble(ens, 0.01, sim)\n",
    "    sim.run(1.4)\n",
    "plot()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Not much happened. Let's bump this up to 10% of the 225 neurons."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "with nengo.Simulator(model) as sim:\n",
    "    ablate_ensemble(ens, 0.1, sim)\n",
    "    sim.run(1.4)\n",
    "plot()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Still not bad, but getting worse. How about 25%?"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "with nengo.Simulator(model) as sim:\n",
    "    ablate_ensemble(ens, 0.25, sim)\n",
    "    sim.run(1.4)\n",
    "plot()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "To verify that this is indeed working as expected,\n",
    "we can ablate all of the neurons and confirm that\n",
    "there is no activity in the ensemble."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "with nengo.Simulator(model) as sim:\n",
    "    ablate_ensemble(ens, 1.0, sim)\n",
    "    sim.run(1.4)\n",
    "plot()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "If we remove the negative bias current,\n",
    "we can see that the neurons still have background activity,\n",
    "but do not respond to input."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "with nengo.Simulator(model) as sim:\n",
    "    ablate_ensemble(ens, 1.0, sim, bias=False)\n",
    "    sim.run(1.4)\n",
    "plot()"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 2",
   "language": "python",
   "name": "python2"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 2
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython2",
   "version": "2.7.10"
  },
  "widgets": {
   "state": {
    "0132386e12fe4fb8a06dfb36057dfff2": {
     "views": []
    },
    "01b509b58e0c43268985c02b6f917f55": {
     "views": []
    },
    "024f20e662c64f68890a529db82350d5": {
     "views": []
    },
    "07773b3ab7624702abfa0300da154a7b": {
     "views": [
      {
       "cell_index": 13
      }
     ]
    },
    "09556ef964d240a891d156f5d698dfc6": {
     "views": []
    },
    "0b88dc0dd3cb41bc92eb6346399749f2": {
     "views": [
      {
       "cell_index": 9
      }
     ]
    },
    "0c6ebbb2d44a4d7c8cde28e44d0fdd82": {
     "views": [
      {
       "cell_index": 9
      }
     ]
    },
    "0ed3c5a16d734b41be94a9a6f3d29ab9": {
     "views": [
      {
       "cell_index": 11
      }
     ]
    },
    "15612c25342649b1a5d3efefcadfcfa9": {
     "views": []
    },
    "170712c4783349db831bc818592d1e18": {
     "views": []
    },
    "297cb3f1e28e492fa26a20f13fb7b8d8": {
     "views": []
    },
    "29968f61b9684f6d86a39d86f7a7b6e6": {
     "views": []
    },
    "2c044758366343b091d3576ca92fe38c": {
     "views": []
    },
    "2d8fd54f06614d76b3fff013e56bcb6a": {
     "views": []
    },
    "2fd2c4d89f364143a0de5946b000ea55": {
     "views": []
    },
    "3102c2f7d9ae47fcaafce1b62353794c": {
     "views": [
      {
       "cell_index": 9
      }
     ]
    },
    "35109ee1d3104936a8a626887c2678ca": {
     "views": [
      {
       "cell_index": 13
      }
     ]
    },
    "36880db395c741169560456766361b55": {
     "views": []
    },
    "36e2e3038c1f4de4b9294dfcd231031a": {
     "views": [
      {
       "cell_index": 17
      }
     ]
    },
    "3c4092f51798490caadfaa89e7b6d4cd": {
     "views": []
    },
    "4f90307d25cc443cb7b9292715cb5884": {
     "views": [
      {
       "cell_index": 17
      }
     ]
    },
    "5231fca38d1f493fbd19777d22c4f8d2": {
     "views": []
    },
    "52dfe0466dc54224ac7975e07f712d1c": {
     "views": [
      {
       "cell_index": 3
      }
     ]
    },
    "53af916f99354835ac0901ff248ce71a": {
     "views": []
    },
    "5796f25ae2f44d02be4a84f6dc9f64b3": {
     "views": []
    },
    "58d5d031e2fd44e284dc7d95e3ed7c49": {
     "views": []
    },
    "5c74a9f623714ddd94571248019d5daf": {
     "views": [
      {
       "cell_index": 9
      }
     ]
    },
    "5ebc646f0e594243b6b95ebc1e637897": {
     "views": []
    },
    "5fb7d1e40deb4e5a824212ab0fc17bf1": {
     "views": [
      {
       "cell_index": 13
      }
     ]
    },
    "6438c32fea944dbabd8adfa0ce2aabb4": {
     "views": []
    },
    "64cd11098d2d45f2b530a1734fc46b5e": {
     "views": []
    },
    "6508973d58f64d9190d581a455afcabf": {
     "views": []
    },
    "6dc9b81d25b949f18e7ddffb9906424d": {
     "views": []
    },
    "73cd3dfaf6074254bd371e27b539d3fe": {
     "views": [
      {
       "cell_index": 15
      }
     ]
    },
    "7bb2d37354354d65b02c9e3e9c651647": {
     "views": []
    },
    "7d3c0c8a6bcd4dfeacbc54bb7c6f85ed": {
     "views": [
      {
       "cell_index": 3
      }
     ]
    },
    "7e3591d7f98a4a7da8cd2c6a17002d15": {
     "views": []
    },
    "82c0e0526b9843108a2e5a82ff0613f9": {
     "views": []
    },
    "8319c94e145648259db9e5a69283c0b3": {
     "views": []
    },
    "8a06b559a93f42ff88755fcf16f42be3": {
     "views": []
    },
    "9490c281b2b047618bb4b43666b867d7": {
     "views": []
    },
    "977afbe3b3874be18ccead6b5de94894": {
     "views": []
    },
    "9bd20272a72745cf80e1aaea223845ae": {
     "views": []
    },
    "9c6f8de1066c4560ae0338f2a6b7a81a": {
     "views": [
      {
       "cell_index": 13
      }
     ]
    },
    "9d6dd299741145a8b07fe99c3c5f0e36": {
     "views": []
    },
    "9eeea4fc92f84754be27ef3fe8983ae2": {
     "views": [
      {
       "cell_index": 15
      }
     ]
    },
    "a0203908050e42368e7f005a680bda7d": {
     "views": [
      {
       "cell_index": 15
      }
     ]
    },
    "a57eccc5a3e044a6af90fae6c4428617": {
     "views": [
      {
       "cell_index": 15
      }
     ]
    },
    "ac92b91d0c0c4125af4b9cb08fe165c3": {
     "views": []
    },
    "b5236806912e47f496372dd305b9c16f": {
     "views": [
      {
       "cell_index": 11
      }
     ]
    },
    "b7225e6796744296a114c742a4d11613": {
     "views": []
    },
    "ba8e6bea218d424ab7748eef4af85c1b": {
     "views": []
    },
    "c27c6bd9d77d496c9b3f1a84cb2a9ed5": {
     "views": []
    },
    "c5a38416082545d79435d95c941e7491": {
     "views": []
    },
    "c9f4abf34aa044eb92ba7f81f8e4038b": {
     "views": []
    },
    "cb4ab9ce34b643c9844c7b8c6a84f0d7": {
     "views": []
    },
    "ce9da041f6c44ccd8f9cbae499e200af": {
     "views": [
      {
       "cell_index": 11
      }
     ]
    },
    "d0a2d3b1b2084142a29b62c2992f425c": {
     "views": [
      {
       "cell_index": 13
      }
     ]
    },
    "d0fecee0d4e04c90b30561a84aaf0bb2": {
     "views": []
    },
    "d4a25dba94b64db0bfa5a3d787f2dc28": {
     "views": [
      {
       "cell_index": 13
      }
     ]
    },
    "da5ba4768d61491fb09c1cb90b1fa432": {
     "views": []
    },
    "dae8857db8784c4a8adbb4679cecdb49": {
     "views": []
    },
    "dd488e3dac0f4bc7b8c4336f642b1407": {
     "views": []
    },
    "ddd0ed1a24e64d4d9fc17c5c51247d69": {
     "views": [
      {
       "cell_index": 13
      }
     ]
    },
    "e04ad5abbac74225a5848b91a13c7f99": {
     "views": []
    },
    "e08ea6d28d434280b0c8f47c33303845": {
     "views": [
      {
       "cell_index": 13
      }
     ]
    },
    "e5454178f8cd42e1b1dcf115cbdfd4e8": {
     "views": []
    },
    "e6ecc7ecb6984676b3c2d412095e43eb": {
     "views": []
    },
    "ee2fcc08a6d1483cad7e043331833fa4": {
     "views": [
      {
       "cell_index": 13
      }
     ]
    },
    "f5b04399053a4b8eaf4f8900480d8f59": {
     "views": []
    },
    "f803ee4799a34dbd96e6aa473748e519": {
     "views": []
    },
    "f9d211e425284857bb374ff502771313": {
     "views": []
    }
   },
   "version": "1.1.2"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 0
}
